import logging
import os
import sys
from datetime import datetime
from logging import Formatter
from logging.handlers import TimedRotatingFileHandler

import colorlog
from colorlog import ColoredFormatter
from rich.console import Console
from rich.logging import RichHandler


def formater() -> Formatter:
    """
    日志格式，字段
    logging模块常用format格式说明
    %(levelno)s: 打印日志级别的数值
    %(levelname)s: 打印日志级别名称
    %(pathname)s: 打印当前执行程序的路径，其实就是sys.argv[0]
    %(filename)s: 打印当前执行程序名，python如：login.py
    %(funcName)s: 打印日志的当前函数
    %(lineno)d: 打印日志的当前行号,在第几行打印的日志
    %(asctime)s: 打印日志的时间
    %(thread)d: 打印线程ID
    %(threadName)s: 打印线程名称
    %(process)d: 打印进程ID
    %(message)s: 打印日志信息
    使用前理解：
    logging.basicConfig函数各参数:
    filename: 指定日志文件名，如my.log 或my.txt
    filemode: 和file函数意义相同，指定日志文件的打开模式，'w'或'a'
    format: 指定输出的格式和内容，format可以输出很多有用信息，如下例所示:
    datefmt: 指定时间格式，同time.strftime()
    level: 设置日志级别，默认为logging.WARNING
    stream: 指定将日志的输出流，可以指定输出到sys.stderr,sys.stdout或者文件，默认输出到sys.stderr，当stream和filename同时指定时，stream被忽略
    """
    formatter = logging.Formatter(
        fmt="%(levelname)s - %(asctime)s - %(threadName)s %(name)s - %(filename)s %(funcName)s %(lineno)s行 - %(message)s",
        datefmt="%Y-%m-%d %H:%M:%S",
    )
    return formatter


def color_formater() -> ColoredFormatter:
    """
    彩色格式，字段，颜色
    """
    formatter = colorlog.ColoredFormatter(
        fmt="%(log_color)s%(levelname)s - %(asctime)s - %(threadName)s %(name)s - %(filename)s %(funcName)s %(lineno)s行 - %(message)s",
        datefmt="%Y-%m-%d %H:%M:%S",
        log_colors={
            "DEBUG": "cyan",
            "INFO": "green",
            "WARNING": "yellow",
            "ERROR": "red",
            "CRITICAL": "bold_red",
        },
    )
    return formatter


def console_handler(level=logging.INFO):
    """
    控制台输出
    """
    stream_handler = logging.StreamHandler()
    stream_handler.setFormatter(color_formater())
    stream_handler.setLevel(level)
    return stream_handler


def color2_formater() -> ColoredFormatter:
    formatter = colorlog.ColoredFormatter(
        fmt="%(log_color)s%(threadName)s - %(filename)s:%(funcName)s:%(lineno)s - %(message)s",
        datefmt="%Y-%m-%d %H:%M:%S",
        log_colors={
            "DEBUG": "cyan",
            "INFO": "green",
            "WARNING": "yellow",
            "ERROR": "red",
            "CRITICAL": "bold_red",
        },
    )
    return formatter


def console2_handler(level=logging.INFO):
    """
    控制台输出 - 使用RichHandler替代StreamHandler
    """
    rich_handler = RichHandler(
        show_time=True,
        show_path=False,
        markup=False,
        rich_tracebacks=True,
        console=Console(width=180)
    )
    rich_handler.setFormatter(color2_formater())
    rich_handler.setLevel(level)
    return rich_handler


def file_hander(level=logging.INFO, count=7):
    """
    日期作为日志文件名
    """
    # 测试:每3秒1个，最多保留5个
    # time_rotate_file = TimedRotatingFileHandler(filename='daily.log', when='S', interval=3, backupCount=5)
    # 当前文件目录
    current_dir = os.path.dirname(os.path.abspath(__file__))
    # 上层目录
    root_dir = os.path.dirname(current_dir)
    # 创建日志目录
    log_dir = os.path.join(root_dir, "logs")
    os.makedirs(log_dir, exist_ok=True)
    # 日期作为日志文件名
    log_path = os.path.join(log_dir, datetime.now().strftime("%Y-%m-%d.log"))
    # 每天1个，最多保留5个
    time_rotate_file = TimedRotatingFileHandler(
        filename=log_path, when="D", backupCount=count
    )
    time_rotate_file.setFormatter(formater())
    time_rotate_file.setLevel(level)
    return time_rotate_file


def uncatch_exception(exc_type, exc_value, exc_traceback):
    # 设置全局异常钩子
    logging.critical("未捕获的异常", exc_info=(exc_type, exc_value, exc_traceback))


def setup_logging(level=logging.INFO):
    """
    设置全局日志格式
    """
    logging.propagate = False
    # 所有未捕获的异常都会被自动记录
    sys.excepthook = uncatch_exception
    # 创建日志记录器
    log = logging.getLogger()
    # 如果有处理器，先移除它们以覆盖框架默认设置
    if log.hasHandlers():
        log.handlers.clear()
    log.setLevel(level)  # 设置日志级别
    # 添加日志记录器
    log.addHandler(console2_handler(level=level))
    # log.addHandler(file_hander(level=level, count=count))


if __name__ == "__main__":
    # 调用函数设置日志
    setup_logging(logging.DEBUG)
    # 测试日志输出颜色
    logging.debug("这是 DEBUG 消息")
    logging.info("这是 INFO 消息")
    logging.warning("这是 WARNING 消息")
    logging.error("这是 ERROR 消息")
    logging.critical("这是 CRITICAL 消息")
    # 测试异常捕获
    raise RuntimeError("这是一个测试异常")  # 这个异常会被自动记录
